home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Tools / ckchan / ckchan.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  17.0 KB  |  845 lines

  1. /* ckchan.c: standalone channel checker */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Tools/ckchan/RCS/ckchan.c,v 6.0 1991/12/18 20:28:55 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Tools/ckchan/RCS/ckchan.c,v 6.0 1991/12/18 20:28:55 jpo Rel $
  9.  *
  10.  * $Log: ckchan.c,v $
  11.  * Revision 6.0  1991/12/18  20:28:55  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include <pwd.h>
  20. #include <isode/usr.dirent.h>
  21. #include <sys/stat.h>
  22. #include    <signal.h>
  23.  
  24. #include "q.h"
  25. #include "retcode.h"
  26. #include "prm.h"
  27.  
  28.  
  29. extern    void getfpath ();
  30. extern CHAN     *ch_nm2struct();
  31. extern char    *quedfldir;
  32. #define    TABSIZE    6
  33.  
  34. static void     build_chanlist();
  35. static struct my_chan_struct *get_chan();
  36. static struct my_chan_struct *add_chan();
  37. static void order_mtas();
  38. static void add_msg();
  39. static void     add_to_chanlist();
  40. static void     print_chanlist();
  41. static void print_chan();
  42. static void print_mta();
  43. static void print_msg();
  44. static void print_drmta();
  45. static void print_drmsg();
  46. static void dirinit();
  47. static void free_chanlist();
  48. static LIST_RCHAN *getnthchannel();
  49.  
  50. #define TIMETROUBLE    24 * 60 * 60
  51. time_t    timetrouble = TIMETROUBLE;
  52. #define noMTA    "NO MTA!"
  53.  
  54. typedef struct recip_struct {
  55.     char            *recip;
  56.     int            status;
  57.     struct recip_struct    *recip_next;
  58. } Recip_struct;
  59.  
  60. typedef struct msg_struct {
  61.     time_t            age;
  62.     char                    *msg;
  63.     char            *ad_value;
  64.     struct recip_struct    *recips;       
  65.     struct msg_struct       *msg_next;
  66. } Msg_struct;
  67.  
  68. typedef struct mta_struct {
  69.     char             *mta;
  70.     int            nmsgs;
  71.     time_t            oldestmsg;
  72.     struct msg_struct    *msgs;
  73.     struct mta_struct    *mta_next;
  74. } Mta_struct;
  75.  
  76. typedef struct my_chan_struct {
  77.     char            *name;
  78.     struct mta_struct    *mtas;
  79.     struct mta_struct    *drmtas;
  80.     struct my_chan_struct    *chan_next;
  81. } My_chan_struct;
  82.  
  83. int                     all,
  84.             verbose,
  85.             summary;
  86. struct my_chan_struct     *chan_list = NULL;
  87.  
  88. main (argc, argv)
  89. int     argc;
  90. char    **argv;
  91. {
  92.     struct stat    statbuf;
  93.     struct prm_vars prm;
  94.     Q_struct        que;
  95.     ADDR            *sender = NULL;
  96.     ADDR            *recips = NULL;
  97.     int             rcount;
  98.     int        opt,
  99.             flags;
  100.     extern int    optind;
  101.     extern char    *optarg;
  102.     char        **msgs = NULLVP;
  103.     extern char     *quedfldir;
  104.     extern char     *aquefile, *postmaster;
  105.     int        num, i;
  106.     all = FALSE;
  107.     flags = 0;
  108.     verbose = FALSE;
  109.     summary = FALSE;
  110.  
  111.     while ((opt = getopt(argc, argv, "vs")) != EOF) {
  112.         switch (opt) {
  113.             case 'v':
  114.             /* verbose output */
  115.             verbose = TRUE;
  116.             flags++;
  117.             break;
  118.             case 's':
  119.             /* summary output */
  120.             summary = TRUE;
  121.             flags++;
  122.             break;
  123.             default:
  124.             printf("usage : %s [-v] [-s] [ chan ...]\n",argv[0]);
  125.             exit(1);
  126.         }
  127.     }
  128.  
  129.     sys_init(argv[0]);
  130.     (void) signal(SIGPIPE, SIG_DFL);
  131.     dirinit();
  132.     argv += flags + 1;
  133.     
  134.     if (*argv == NULL)
  135.         all=TRUE;
  136.     else
  137.         build_chanlist(argv);
  138.  
  139.     if (stat(quedfldir, &statbuf) != OK) {
  140.         printf("Unable to find spool area\nPlease inform %s\n", postmaster);
  141.         (void) exit(1);
  142.     }
  143.     printf("Please wait while information is processed...");
  144.     fflush(stdout);
  145.     num = i = 0;
  146.     hier_scanQ (quedfldir, NULLCP, &num, &msgs, &i, NULLIFP);
  147.     for (i = 0; i < num; i++) {
  148.         sender = NULL;
  149.         recips = NULL;
  150.         prm_init (&prm);
  151.         q_init(&que);
  152.         if (rp_isbad(rd_msg_file(msgs[i],
  153.                      &prm,&que,
  154.                      &sender,&recips,
  155.                      &rcount,
  156.                      RDMSG_RDONLY))) {
  157.             rd_end();
  158.             printf("Bad message %s : rd_msg fails\n",msgs[i]);
  159.         } else {
  160.             rd_end();
  161.             add_to_chanlist(msgs[i],&que);
  162.             q_free(&que);
  163.         }
  164.  
  165.         
  166.  
  167.     }
  168.     printf("done\n");
  169.     print_chanlist();
  170.  
  171.     
  172.     if (num > 0 && msgs != NULLVP)
  173.         free_hier(msgs, num);
  174.         free_chanlist();
  175.     exit(0);
  176. }
  177.  
  178. static void dirinit()
  179. {
  180.     if (chdir (quedfldir) < 0)
  181.         err_abrt (RP_LIO,
  182.               " Unable to change directory to '%s'",
  183.               quedfldir);
  184. }
  185.  
  186. static char    *time_t2str(in)
  187. time_t  in;
  188. {
  189.     char    buf[BUFSIZ];
  190.     time_t    result;
  191.     buf[0] = '\0';
  192.     
  193.     if (in < 0)
  194.         return strdup("still in the womb");
  195.  
  196.     if ((result = in / (60 * 60 * 24)) != 0) {
  197.         sprintf(buf, "%d days",result);
  198.         in = in % (60 * 60 * 24);
  199.     }
  200.  
  201.     if ((result = in / (60 * 60)) != 0) {
  202.         sprintf(buf, (buf[0] == '\0') ? "%s%d hrs" : "%s %d hrs",
  203.             buf, result);
  204.         in = in % (60 * 60);
  205.     }
  206.     if ((result = in / 60) != 0) {
  207.         sprintf(buf, (buf[0] == '\0') ? "%s%d mins" : "%s %d mins",
  208.             buf, result);
  209.         in = in % 60;
  210.     }
  211.  
  212.     if (buf[0] == '\0' && in != 0)
  213.         sprintf(buf, "%d secs", in);
  214.     if (buf[0] == '\0')
  215.         sprintf(buf, "just born");
  216.     return strdup(buf);
  217. }
  218.  
  219. static char    *time_t2RFC(in)
  220. time_t    in;
  221. {
  222.     char    buf[BUFSIZ],
  223.         *str;
  224.     time_t    curr,
  225.         delta;
  226.  
  227.     curr = time(0);
  228.     delta = curr - in;
  229.     
  230.     str = time_t2str(delta);
  231.     sprintf(buf,"%s%s",
  232.         str,
  233.         (delta > timetrouble) ? " *****" : "");
  234.     free(str);
  235.     return strdup(buf);
  236. }
  237.  
  238. static void build_chanlist(chans)
  239. char            **chans;
  240. {
  241.     CHAN                    *chan;
  242.     char                    **ix = chans;
  243.     while (*ix != NULL) {
  244.         if (lexequ(*ix, "ALL") == 0)
  245.             all = TRUE;
  246.         else if ((chan = ch_nm2struct(*ix)) == NULLCHAN) 
  247.             printf("unknown channel '%s'\n",*ix);
  248.         else 
  249.             (void) add_chan(chan);
  250.         ix++;
  251.     }
  252. }
  253.  
  254.  
  255. static struct mta_struct *get_mta(list, mta)
  256. struct mta_struct    *list;
  257. char            *mta;
  258. {
  259.     struct mta_struct    *ix = list;
  260.     
  261.     while (ix != NULL && (strcmp(ix->mta,mta) != 0))
  262.         ix = ix -> mta_next;
  263.     return ix;
  264. }
  265.  
  266. static struct msg_struct *get_msg(list, key)
  267. struct msg_struct     *list;
  268. char            *key;
  269. {
  270.     struct msg_struct    *ix = list;
  271.  
  272.     while (ix != NULL && (strcmp(ix->msg,key) != 0))
  273.         ix = ix -> msg_next;
  274.     return ix;
  275. }
  276.  
  277. static struct my_chan_struct *get_chan(chan)
  278. CHAN    *chan;
  279. {
  280.     struct my_chan_struct     *ix = chan_list;
  281.  
  282.     while ((ix != NULL) && (strcmp(ix->name,chan->ch_name) != 0))
  283.         ix = ix->chan_next;
  284.     return ix;
  285. }
  286.  
  287. static struct my_chan_struct *add_chan(chan)
  288. CHAN    *chan;
  289. {
  290.     struct my_chan_struct     *temp = (struct my_chan_struct *) calloc(1, sizeof(*temp));
  291.     temp->name = strdup(chan->ch_name);
  292.     temp->chan_next = chan_list;
  293.     chan_list = temp;
  294.     return chan_list;
  295. }
  296.  
  297. static void add_recip(plist, adr)
  298. struct recip_struct    **plist;
  299. ADDR            *adr;
  300. {
  301.     struct recip_struct    *ret = (struct recip_struct *) calloc(1, sizeof(*ret));
  302.  
  303.     ret -> recip = strdup(adr -> ad_value);
  304.     ret -> status = adr -> ad_status;
  305.  
  306.     ret -> recip_next = *plist;
  307.     *plist = ret;
  308. }
  309.  
  310. static struct msg_struct *new_msg(msg, que, recip)
  311. char        *msg;
  312. Q_struct    *que;
  313. ADDR        *recip;
  314. {
  315.     struct msg_struct    *ret = (struct msg_struct *) calloc(1, sizeof(*ret));
  316.  
  317.     ret -> age = utc2time_t(que -> queuetime);
  318.     ret -> msg = strdup(msg);
  319.     ret -> ad_value = strdup(que->Oaddress->ad_value);
  320.     add_recip(&ret -> recips, recip);
  321.     
  322.     return ret;
  323. }
  324. static void add_msg(plist, msg)
  325. struct msg_struct    **plist,
  326.             *msg;
  327. {
  328.     struct msg_struct    *ix = *plist;
  329.  
  330.     if (*plist == NULL
  331.         || (*plist) -> age > msg -> age) {
  332.         msg -> msg_next = *plist;
  333.         *plist = msg;
  334.     } else {
  335.         while ( ix -> msg_next != NULL
  336.                && ix -> msg_next -> age <= msg -> age)
  337.             ix = ix -> msg_next;
  338.         msg -> msg_next = ix -> msg_next;
  339.         ix -> msg_next = msg;
  340.     }
  341. }
  342.  
  343. #define    NEW    0
  344. #define OLD    1
  345.  
  346. static int update_msg(plist,msg,que,recip)
  347. struct msg_struct    **plist;
  348. char                *msg;
  349. Q_struct            *que;
  350. ADDR                *recip;
  351. {
  352.     struct msg_struct    *temp;
  353.  
  354.     if ((temp = get_msg(*plist,msg)) == NULL) {
  355.         temp = new_msg(msg, que, recip);
  356.         add_msg(plist, temp);
  357.         return NEW;
  358.     } else {
  359.         add_recip(&temp->recips, recip);
  360.         return OLD;
  361.     }
  362. }
  363.  
  364. static void update_mta(mta, msg, que, recip)
  365. struct mta_struct    *mta;
  366. char            *msg;
  367. Q_struct        *que;
  368. ADDR            *recip;
  369. {
  370.     time_t    qtime;
  371.  
  372.     qtime = utc2time_t(que->queuetime);
  373.     if (qtime < mta -> oldestmsg)
  374.         mta -> oldestmsg = qtime;
  375.     if (update_msg(&mta->msgs, msg, que, recip) == NEW)
  376.         mta->nmsgs++;
  377.  
  378. }
  379.  
  380. static void new_mta(plist, msg, que, recip, inmta)
  381. struct mta_struct    **plist;
  382. char            *msg;
  383. Q_struct        *que;
  384. ADDR            *recip;
  385. char            *inmta;
  386. {
  387.     struct mta_struct *temp = (struct mta_struct *) calloc(1, sizeof(*temp));
  388.     if (recip ->ad_outchan && recip->ad_outchan->li_mta != NULLCP)
  389.         temp -> mta = strdup(recip -> ad_outchan -> li_mta);
  390.     else if (inmta != NULL)
  391.         temp -> mta = strdup(inmta);
  392.     else
  393.         temp->mta = strdup(noMTA);
  394.  
  395.     temp -> nmsgs = 1;
  396.     temp -> oldestmsg = utc2time_t(que -> queuetime);
  397.     update_msg(&temp->msgs, msg, que, recip);
  398.     temp -> mta_next = *plist;
  399.     *plist = temp;
  400. }
  401.  
  402. static void add_mta(msg,que,recip,chan)
  403. char            *msg;
  404. Q_struct        *que;
  405. ADDR            *recip;
  406. CHAN            *chan;
  407. {
  408.     struct my_chan_struct    *temp;
  409.     struct mta_struct    *mta;
  410.     char            *chmta;
  411.     if ((temp = get_chan(chan)) == NULL && all == TRUE)
  412.         temp = add_chan(chan);
  413.  
  414.     if (temp == NULL)
  415.     /* not interested in this channel */
  416.         return;
  417.  
  418.     if (recip->ad_outchan && recip->ad_outchan->li_mta)
  419.         chmta = recip->ad_outchan->li_mta;
  420.     else
  421.         chmta = noMTA;
  422.     if ((mta = get_mta(temp -> mtas,chmta)) == NULL)
  423.         new_mta(&(temp -> mtas),
  424.             msg,
  425.             que,
  426.             recip,
  427.             chmta);
  428.     else 
  429.         update_mta(mta,msg,que,recip);
  430. }
  431.  
  432. static void add_drmta(msg,que,sender,chan)
  433. char            *msg;
  434. Q_struct        *que;
  435. ADDR            *sender;
  436. LIST_RCHAN    *chan;
  437. {
  438.     struct my_chan_struct    *temp;
  439.     struct mta_struct    *mta;
  440.     char            *chmta;
  441.  
  442.     if (chan->li_chan == NULL 
  443.         || chan->li_chan->ch_name == NULL) {
  444.             PP_OPER(NULL, ("Outchan for DR not set (sorry can't be of more help !)"));
  445.             return;
  446.         }
  447.     if ((temp = get_chan(chan->li_chan)) == NULL && all == TRUE)
  448.         temp = add_chan(chan->li_chan);
  449.  
  450.     if (temp == NULL)
  451.     /* not interested in this channel */
  452.         return;
  453.     if (sender->ad_outchan && sender->ad_outchan->li_mta)
  454.         chmta = sender->ad_outchan->li_mta;
  455.     else if (chan->li_mta)
  456.         chmta = chan->li_mta;
  457.     else
  458.         chmta = noMTA;
  459.     if ((mta = get_mta(temp -> drmtas, chmta)) == NULL)
  460.         new_mta(&(temp -> drmtas),
  461.             msg,
  462.             que,
  463.             sender,
  464.             chmta);
  465.     else 
  466.         update_mta(mta,msg,que,sender);
  467. }
  468.           
  469. static void add_to_chanlist(msg,que)
  470. char            *msg;
  471. Q_struct        *que;
  472. {
  473.     ADDR            *ix = que->Raddress;
  474.     LIST_RCHAN      *chan,
  475.             *chanix;
  476.     while (ix != NULL) {
  477.         if (ix -> ad_status == AD_STAT_DRWRITTEN
  478.             || ix -> ad_status == AD_STAT_DRREQUIRED) {
  479.             if ((chan = getnthchannel(que->Oaddress->ad_fmtchan,
  480.                           que->Oaddress->ad_rcnt)) != NULL)
  481.                 add_drmta(msg,que, que->Oaddress, chan);
  482.             else {
  483.                 chanix = que->Oaddress->ad_outchan;
  484.  
  485.                 while (chanix != NULL) {
  486.                     add_drmta(msg, que, que->Oaddress, chanix);
  487.                     chanix = chanix->li_next;
  488.                 }
  489.             }
  490.  
  491.         } else if (ix -> ad_status != AD_STAT_DONE) {
  492.             /* must be on a channel */
  493.             /* check reformaters */
  494.             if ((chan = getnthchannel(ix->ad_fmtchan, ix -> ad_rcnt)) != NULL) 
  495.                 /* still needs reformating */
  496.                 add_mta(msg,que,ix,chan->li_chan);
  497.             else {
  498.                 /* on outbound channel */
  499.                 chanix = ix->ad_outchan;
  500.  
  501.                 while (chanix != NULL) {
  502.                     add_mta(msg,que,ix,chanix->li_chan);
  503.                     chanix = chanix->li_next;
  504.  
  505.                 }
  506.             }
  507.         }
  508.         ix = ix->ad_next;
  509.     }
  510. }
  511.  
  512. int    total_nummsgs = 0, total_nummtas = 0;
  513. time_t    veryoldest = 0;
  514. int    total_numdrs = 0, total_numdrmtas = 0;
  515. time_t    veryoldestdr = 0;
  516.  
  517. static void print_chanlist()
  518. {
  519.     struct my_chan_struct *ix = chan_list;
  520.     
  521.  
  522.     while (ix != NULL) {
  523.         print_chan(ix);
  524.         ix = ix -> chan_next;
  525.     }
  526.     if (summary == TRUE && 
  527.         (total_numdrs != 0 || total_nummsgs != 0)) {
  528.         char    *timestring;
  529.         printf ("\nTotals\n======\n");
  530.         if (total_nummsgs != 0) {
  531.             timestring = time_t2RFC(veryoldest);
  532.             printf("%d msgs on %d mtas (oldest %s)\n",
  533.                    total_nummsgs, total_nummtas, timestring);
  534.             free(timestring);
  535.         }
  536.         if (total_numdrs != 0) {
  537.             timestring = time_t2RFC(veryoldestdr);
  538.             printf("%d DRs on %d mtas (oldest %s)\n",
  539.                    total_numdrs, total_numdrmtas, timestring);
  540.             free(timestring);
  541.         }
  542.     }
  543.             
  544. }        
  545.  
  546. static void print_chan(chanptr)
  547. struct my_chan_struct    *chanptr;
  548. {
  549.     struct mta_struct    *ix;
  550.     int    num_mtas = 0, num_msgs = 0;
  551.     time_t    oldestmsg = 0;
  552.     int    num_drmtas = 0, num_drs = 0;
  553.     time_t    oldestdr = 0;
  554.     char    *timestring;
  555.  
  556.     if (summary == TRUE) {
  557.         for (ix = chanptr->mtas; 
  558.              ix != (struct mta_struct *) NULL;
  559.              ix = ix -> mta_next) {
  560.             num_mtas++;
  561.             num_msgs += ix -> nmsgs;
  562.             if (ix -> oldestmsg < oldestmsg ||
  563.                 oldestmsg == 0)
  564.                 oldestmsg = ix -> oldestmsg;
  565.         }
  566.         total_nummtas += num_mtas;
  567.         total_nummsgs += num_msgs;
  568.         if (oldestmsg < veryoldest ||
  569.             veryoldest == 0)
  570.             veryoldest = oldestmsg;
  571.  
  572.         for (ix = chanptr -> drmtas;
  573.              ix != (struct mta_struct *) NULL;
  574.              ix = ix -> mta_next) {
  575.             num_drmtas++;
  576.             num_drs += ix -> nmsgs;
  577.             if (ix -> oldestmsg < oldestdr ||
  578.                 oldestdr == 0)
  579.                 oldestdr = ix -> oldestmsg;
  580.         }
  581.         total_numdrmtas += num_drmtas;
  582.         total_numdrs += num_drs;
  583.         if (oldestdr < veryoldestdr ||
  584.             veryoldestdr == 0)
  585.             veryoldestdr = oldestdr;
  586.         printf ("%s ", chanptr->name);
  587.         if (num_msgs != 0) {
  588.             timestring = time_t2RFC(oldestmsg);
  589.             printf("%d msgs on %d mtas (oldest %s)\n",
  590.                    num_msgs, num_mtas, timestring);
  591.             free(timestring);
  592.         }
  593.         if (num_drs != 0) {
  594.             if (num_msgs != 0)
  595.                 printf ("%*c",strlen(chanptr->name), ' ');
  596.             timestring = time_t2RFC(oldestdr);
  597.             printf("%d DRs on %d mtas (oldest %s)\n",
  598.                    num_drs, num_drmtas, timestring);
  599.             free(timestring);
  600.         }
  601.     } else {
  602.         printf("%s\n",chanptr->name);
  603.     
  604.         order_mtas(&(chanptr->mtas));
  605.         if ((ix = chanptr -> mtas) != NULL)
  606.             printf("%*smessages\n",TABSIZE/2,"");
  607.         while (ix != NULL) {
  608.             print_mta(ix);
  609.             ix = ix -> mta_next;
  610.         }
  611.     
  612.         order_mtas(&(chanptr->drmtas));
  613.         if ((ix = chanptr -> drmtas) != NULL)     
  614.             printf("%*sDRs\n",TABSIZE/2,"");
  615.         while (ix != NULL) {
  616.             print_drmta(ix);
  617.             ix = ix -> mta_next;
  618.         }
  619.     }
  620. }
  621.  
  622. static void print_mta(mta)
  623. struct mta_struct    *mta;
  624. {
  625.     struct msg_struct    *ix;
  626.     char            *timestring;
  627.     if (verbose == TRUE) {
  628.         printf("%*s%s\n",TABSIZE,"",mta->mta);
  629.         ix = mta->msgs;
  630.         while (ix != NULL) {
  631.             print_msg(ix);
  632.             ix = ix -> msg_next;
  633.         }
  634.     } else {
  635.         timestring = time_t2RFC(mta->oldestmsg);
  636.         printf("%*s%-25s %d%*s%s\n",
  637.                TABSIZE,"",
  638.                mta -> mta,
  639.                mta -> nmsgs,
  640.                TABSIZE,"",
  641.                timestring);
  642.         free(timestring);
  643.     }
  644. }
  645.  
  646. static void print_drmta(mta)
  647. struct mta_struct    *mta;
  648. {
  649.     struct msg_struct    *ix;
  650.     char            *timestring;
  651.     
  652.     if (verbose == TRUE) {
  653.         printf("%*s%s\n",TABSIZE,"",mta->mta);
  654.         ix = mta->msgs;
  655.         while (ix != NULL) {
  656.             print_drmsg(ix);
  657.             ix = ix -> msg_next;
  658.         }
  659.     } else {
  660.         timestring = time_t2RFC(mta->oldestmsg);
  661.         printf("%*s%-25s %d%*s%s\n",
  662.                TABSIZE,"",
  663.                mta -> mta,
  664.                mta -> nmsgs,
  665.                TABSIZE,"",
  666.                timestring);
  667.         free(timestring);
  668.     }
  669. }
  670. char    *status_str[] = {
  671.     "unknown",
  672.     "pend",
  673.     "dr req",
  674.     "dr written",
  675.     "done"
  676.     };
  677.  
  678. static void print_msg(msg)
  679. struct msg_struct    *msg;
  680. {
  681.     char            *timestring = time_t2RFC(msg->age);
  682.     struct recip_struct    *ix = msg -> recips;
  683.  
  684.     printf("%*s%-25s %s\n",
  685.            2*TABSIZE,"",
  686.            msg->msg,
  687.            timestring);
  688.     printf("%*sfrom %-30s",
  689.            3*TABSIZE,"",
  690.            msg->ad_value);           
  691.  
  692.     if (ix == NULL)
  693.         printf (" %s\n", status_str[AD_STAT_DRWRITTEN]);
  694.     else
  695.         printf("\n");
  696.  
  697.     while (ix != NULL) {
  698.         printf("%*sto %-30s %s\n",
  699.                3*TABSIZE,"",
  700.                ix -> recip,
  701.                status_str[ix -> status]);
  702.         ix = ix -> recip_next;
  703.     }
  704.     free(timestring);
  705. }
  706.  
  707. static void print_drmsg(msg)
  708. struct msg_struct    *msg;
  709. {
  710.     char            *timestring = time_t2RFC(msg->age);
  711.     struct recip_struct    *ix = msg -> recips;
  712.  
  713.     printf("%*s%-25s %s\n",
  714.            2*TABSIZE,"",
  715.            msg->msg,
  716.            timestring);
  717.  
  718.     printf("%*sto %-30s\n",
  719.            3*TABSIZE,"",
  720.            msg->ad_value);           
  721.  
  722.     while (ix != NULL) {
  723.         printf("%*sfrom recip %-30s\n",
  724.                3*TABSIZE,"",
  725.                ix -> recip);
  726.         ix = ix -> recip_next;
  727.     }
  728.     free(timestring);
  729. }
  730.  
  731. static LIST_RCHAN *getnthchannel(chans,num)
  732. LIST_RCHAN      *chans;
  733. int             num;
  734. {
  735.     LIST_RCHAN      *ix = chans;
  736.     int             icount = 0;
  737.  
  738.     while ((ix != NULL) && (icount++ < num)) 
  739.         ix = ix->li_next;
  740.  
  741.     return ix;
  742. }
  743.  
  744. static void insert_mta(plist, mta)
  745. struct mta_struct    **plist,
  746.             *mta;
  747. {
  748.     struct mta_struct    *ix = *plist;
  749.  
  750.     if (*plist == NULL
  751.         || (*plist) -> oldestmsg > mta -> oldestmsg) {
  752.         mta -> mta_next = *plist;
  753.         *plist = mta;
  754.     } else {
  755.         while ( ix -> mta_next != NULL
  756.                && ix -> mta_next -> oldestmsg <= mta -> oldestmsg)
  757.             ix = ix -> mta_next;
  758.         mta -> mta_next = ix -> mta_next;
  759.         ix -> mta_next = mta;
  760.     }
  761. }
  762.  
  763. static void order_mtas(plist)
  764. struct mta_struct    **plist;
  765. {
  766.     struct mta_struct    *new = NULL,
  767.                 *head = *plist,
  768.                 *tail;
  769.  
  770.     while (head != NULL) {
  771.         tail = head -> mta_next;
  772.         insert_mta(&new, head);
  773.         head = tail;
  774.     }
  775.  
  776.     *plist = new;
  777. }
  778.  
  779. /*   */
  780.  
  781. static void free_recips(recips)
  782. struct recip_struct    *recips;
  783. {
  784.     struct recip_struct    *temp;
  785.     
  786.     while (recips != NULL) {
  787.         temp = recips;
  788.         if (temp->recip)
  789.             free(temp->recip);
  790.         recips = temp -> recip_next;
  791.         free((char *) temp);
  792.     }
  793. }
  794.  
  795. static void free_msgs (msgs)
  796. struct msg_struct    *msgs;
  797. {
  798.     struct msg_struct    *temp;
  799.  
  800.     while (msgs != NULL) {
  801.         temp = msgs;
  802.         if (temp->msg)
  803.             free(temp->msg);
  804.         if (temp->ad_value)
  805.             free(temp->ad_value);
  806.         if (temp->recips)
  807.             free_recips(temp->recips);
  808.         msgs = temp->msg_next;
  809.         free((char *) temp);
  810.     }
  811. }
  812.  
  813. static void free_mtas(mtas)
  814. struct mta_struct    *mtas;
  815. {
  816.     struct mta_struct    *temp;
  817.  
  818.     while (mtas != NULL) {
  819.         temp = mtas;
  820.         if (mtas->mta)
  821.             free(mtas->mta);
  822.         if (mtas->msgs)
  823.             free_msgs(mtas->msgs);
  824.         mtas = mtas->mta_next;
  825.         free((char *) temp);
  826.     }
  827. }
  828.  
  829. static void free_chanlist()
  830. {
  831.     struct my_chan_struct    *temp;
  832.     while (chan_list != NULL) {
  833.         temp = chan_list;
  834.         if (temp -> name)
  835.             free(temp->name);
  836.         if (temp->mtas)
  837.             free_mtas(temp->mtas);
  838.         if (temp->drmtas)
  839.             free_mtas(temp->drmtas);
  840.         chan_list = temp->chan_next;
  841.         free((char *) temp);
  842.     }
  843. }
  844.        
  845.